import React, { useEffect, useState, type ReactElement, useRef } from 'react'
import { Rnd } from 'react-rnd'
import { type LyricWordProps, type LyricLineProps, type LyricProps, type DesktopLyricProps } from 'src/interface'

async function initlyric (lyric: string | undefined): Promise<string> {
  if (lyric === undefined) {
    return ''
  }

  if (lyric.startsWith('[ti:') || lyric.startsWith('[ar:') || lyric.startsWith('[al:') || lyric.startsWith('[by:') || lyric.startsWith('[offset:') || lyric.startsWith('[00:')) {
    return lyric
  }

  if (/^(https?|\/)[^\s/$.?#].[^\s]*/i.test(lyric)) {
    return await fetch(lyric).then(async response => await response.text())
  }
  return ''
}

function Lyric (props: LyricProps): ReactElement {
  const [lyricText, setLyricText] = useState('')
  const [tLyricText, settLyricText] = useState('')
  const [formatLyricData, setFormatLyricData] = useState<LyricLineProps[]>([])
  const [playIndex, setPlayIndex] = useState(0)
  useEffect(() => {
    initlyric(props.lyric).then((data) => { setLyricText(data) }).catch(e => { })
    initlyric(props.tLyric).then((data) => { settLyricText(data) }).catch(e => { })
  }, [props.lyric, props.tLyric])

  useEffect(() => {
    const data: LyricLineProps[] = []

    const lyricLines = lyricText.split(/\r?\n/)
    const tLyricLines = tLyricText.split(/\r?\n/)

    let tLyricLinesIndex = 0
    lyricLines.forEach(line => {
      const lyricLineWords = [...line.matchAll(/\[\d{2,}:\d{2}\.\d{2}]/g)]
      if (lyricLineWords.length > 0) {
        const formatLineData: LyricLineProps = {
          text: '',
          start: '',
          end: '',
          startTime: 0,
          endTime: 0,
          words: [],
          trans: ''
        }

        for (let i = 0; i < lyricLineWords.length; i++) {
          if (i === 0) {
            formatLineData.startTime = convertTimeToSeconds(lyricLineWords[i][0])
            formatLineData.start = lyricLineWords[i][0]
            for (let j = tLyricLinesIndex; j < tLyricLines.length; j++) {
              if (tLyricLines[j].startsWith(lyricLineWords[i][0])) {
                tLyricLinesIndex = j + 1
                formatLineData.trans = tLyricLines[j].replace(lyricLineWords[i][0], '')
              }
            }
          } else {
            const text = lyricLineWords[i].input?.substring(Number(lyricLineWords[i - 1].index) + 10, lyricLineWords[i].index) + ''
            formatLineData.text += text
            const formatWordData: LyricWordProps = {
              text,
              start: lyricLineWords[i - 1][0],
              end: lyricLineWords[i][0],
              startTime: convertTimeToSeconds(lyricLineWords[i - 1][0]),
              endTime: convertTimeToSeconds(lyricLineWords[i][0]),
              percent: (convertTimeToSeconds(lyricLineWords[i][0]) - formatLineData.startTime) / (convertTimeToSeconds(lyricLineWords[lyricLineWords.length - 1][0]) - formatLineData.startTime)
            }
            formatLineData.words.push(formatWordData)
          }
          if (i === lyricLineWords.length - 1) {
            formatLineData.endTime = convertTimeToSeconds(lyricLineWords[i][0])
            formatLineData.end = lyricLineWords[i][0]
          }
        }
        data.push(formatLineData)
      }
    })
    setFormatLyricData(data)
    console.log(data)
  }, [lyricText, tLyricText])

  function convertTimeToSeconds (timeString: string): number {
    const match = timeString.match(/\[(\d{2}):(\d{2})\.(\d{2})\]/)
    if (match == null) {
      throw new Error('Invalid time format')
    }

    const minutes = parseInt(match[1])
    const seconds = parseInt(match[2])
    const milliseconds = parseInt(match[3])
    const totalSeconds = minutes * 60 + seconds + milliseconds / 100

    return Number(totalSeconds.toFixed(2))
  }

  function formatWidth (lineIndex: number, wordIndex: number): string {
    if (lineIndex !== playIndex) {
      return '0%'
    }
    const word = formatLyricData[lineIndex].words[wordIndex]
    let width = 0
    if (word.startTime <= props.currentTime && word.endTime >= props.currentTime) {
      width = (props.currentTime - word.startTime) / (word.endTime - word.startTime)
    }
    if (word.endTime <= props.currentTime) {
      width = 1
    }
    return (width * 100).toFixed() + '%'
  }

  useEffect(() => {
    for (let i = 0; i < formatLyricData.length; i++) {
      if (props.currentTime >= formatLyricData[i].startTime && props.currentTime <= formatLyricData[i].endTime && playIndex !== i) {
        setPlayIndex(i)
        break
      }
    }
  }, [props.currentTime])

  const renderLyricDom = (): ReactElement => {
    if (props.playMode === 'desktop') {
      return (
        <DesktopLyric emptyLyricDescription={props.emptyLyricDescription} show={props.show} formatLyricData={formatLyricData} playIndex={playIndex} formatWidth={formatWidth} currentTime={props.currentTime} />
      )
    } else {
      return (
        <div className='roll-lyric'>
          {formatLyricData.map((line, lineIndex) => (
            <div key={lineIndex} className='line'>
              {line.words.map((word, wordIndex) => {
                if (lineIndex === playIndex) {
                  return <span key={wordIndex} className="word" style={{ backgroundImage: `linear-gradient(to right, #0EAD51 ${formatWidth(lineIndex, wordIndex)}, #FF5D5E 0%)` }}>{word.text}</span>
                } else {
                  return <span key={wordIndex} className="word" style={{ backgroundImage: 'linear-gradient(to right, #0EAD51 0%, #FF5D5E 0%)' }}>{word.text}</span>
                }
              })}
            </div>
          ))}
        </div>
      )
    }
  }

  return (
    <div className="lyric">
      {renderLyricDom()}
    </div>
  )
}

export function DesktopLyric (props: DesktopLyricProps): ReactElement {
  const [width, setWidth] = useState(600)
  const [height, setHeight] = useState(100)
  const [x, setX] = useState(0)
  const [y, setY] = useState(0)
  const lineRef = useRef<HTMLDivElement>(null)
  const [translateX, setTranslateX] = useState(0)
  useEffect(() => {
    if (lineRef.current !== null) {
      let w = 0
      let translateIndex = 0

      for (let i = 0; i < lineRef.current.children.length; i++) {
        w += (lineRef.current.children[i] as HTMLDivElement).offsetWidth
        if (w > (width - 40) / 2) {
          translateIndex = i
          break
        }
      }

      for (let i = translateIndex + 1; i < lineRef.current.children.length; i++) {
        w = w + (lineRef.current.children[i] as HTMLDivElement).offsetWidth
      }

      if ((w > (width - 40)) && (w - (width - 40)) >= translateX) {
        const words = props.formatLyricData[props.playIndex].words
        for (let i = 0; i < words.length; i++) {
          if (words[i].startTime <= props.currentTime && props.currentTime <= words[i].endTime) {
            if (w > (width - 40) && i >= translateIndex) {
              let tx = (lineRef.current.children[i] as HTMLDivElement).offsetWidth * (props.currentTime - words[i].startTime) / (words[i].endTime - words[i].startTime)
              for (let j = translateIndex; j < i; j++) {
                tx += (lineRef.current.children[j] as HTMLDivElement).offsetWidth
              }
              if ((w - (width - 40)) < tx) {
                tx = w - (width - 40)
              }
              setTranslateX(tx)
              lineRef.current.style.transform = `translateX(-${translateX}px)`
            }
            break
          }
        }
      }
    }
  }, [props.currentTime])

  useEffect(() => {
    setTranslateX(0)
    if (lineRef.current != null) {
      lineRef.current.style.transform = 'translateX(0)'
    }
  }, [props.playIndex])

  return (

    props.show
      ? <Rnd
        className="backtop-lyric"
        minWidth={300}
        maxHeight={150}
        minHeight={60}
        size={{ width, height }}
        position={{ x, y }}
        onDragStop={(e, d) => {
          setX(d.x)
          setY(d.y)
        }}
        onResize={(e, direction, ref, delta, position) => {
          ref.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
          setWidth(ref.offsetWidth)
          setHeight(ref.offsetHeight)
        }}
        onResizeStop={(e, direction, ref, delta, position) => {
          ref.style.backgroundColor = ''
          setX(position.x)
          setY(position.y)
        }}
      >
        <div>
          {/* <Flex className="backtop-lyric-control" justify="end">
              <div className="icon" style={{ float: 'right' }}>
                <CloseIcon size={16}/>
              </div>
            </Flex> */}
          <div className="backtop-lyric-text">
            {props.formatLyricData.length > 0
              ? props.formatLyricData.map((line, lineIndex) => {
                if (lineIndex === props.playIndex) {
                  return <div key={lineIndex}>
                  <div className='line' ref={lineRef} style={{ fontSize: Math.min(width, height) / 2 }}>
                    {line.words.map((word, wordIndex) => (
                      <span key={wordIndex} className="word" style={{ backgroundImage: `linear-gradient(to right, #0EAD51 ${props.formatWidth(lineIndex, wordIndex)}, #FF5D5E 0%)` }}>{word.text}</span>
                    ))}
                  </div>
                  <div className='trans' style={{ fontSize: Math.min(width, height) / 4 }}>
                    <span className="word" style={{ backgroundColor: '#FF5D5E' }}>{line.trans}</span>
                  </div>
                </div>
                } else {
                  return ''
                }
              })
              : (props.emptyLyricDescription ?? <div className="line" style={{ fontSize: Math.min(width, height) / 2, color: '#FF5D5E' }}>暂无歌词</div>)}
          </div>
        </div>
      </Rnd>
      : <></>
  )
}
export default Lyric
